package com.sh.rpc.proxy;

import com.sh.rpc.RpcApplication;
import com.sh.rpc.confige.RpcConfig;
import com.sh.rpc.constant.RpcConstant;
import com.sh.rpc.fault.retry.RetryStrategy;
import com.sh.rpc.fault.retry.RetryStrategyFactory;
import com.sh.rpc.fault.tolerant.ToleranStrategyFactory;
import com.sh.rpc.fault.tolerant.TolerantStrategy;
import com.sh.rpc.loadbalancer.LoadBalanceFactory;
import com.sh.rpc.loadbalancer.LoadBalancer;
import com.sh.rpc.model.RpcRequest;
import com.sh.rpc.model.RpcResponse;
import com.sh.rpc.model.ServiceMetaInfo;
import com.sh.rpc.registry.Registry;
import com.sh.rpc.registry.RegistryFactory;
import com.sh.rpc.serializer.Serializer;
import com.sh.rpc.serializer.SerializerFactory;
import com.sh.rpc.server.tcp.VertxTcpClient;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ServiceProxy implements InvocationHandler {

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//        Serializer serializer = new JdkSerializer();
        Serializer serializer = SerializerFactory.getInstance(RpcApplication.getRpcConfig().getSerializer());

        // 构造请求
        String serviceName = method.getDeclaringClass().getName();
        RpcRequest rpcRequest = RpcRequest.builder()
                .serviceName(method.getDeclaringClass().getName())
                .methodName(method.getName())
                .parameterTypes(method.getParameterTypes())
                .args(args)
                .build();

            // 服务中心中拿到地址
            RpcConfig rpcConfig = RpcApplication.getRpcConfig();
            Registry registry = RegistryFactory.getInstance(rpcConfig.getRegistryConfig().getRegistry());// 获取注册中心
            ServiceMetaInfo serviceMetaInfo = new ServiceMetaInfo();
            serviceMetaInfo.setServiceName(serviceName);
            serviceMetaInfo.setServiceVersion(RpcConstant.DEFAULT_SERVICE_VERSION);
            List<ServiceMetaInfo> serviceMetaInfoList = registry.serviceDiscovery(serviceMetaInfo.getServiceKey());
            if (serviceMetaInfoList == null) {
                throw new RuntimeException("服务未找到");
            }
//            ServiceMetaInfo selectedServiceMetaInfo = serviceMetaInfoList.get(0);// 获取服务信息 取第一个
            LoadBalancer loadBalancer = LoadBalanceFactory.getInstance(rpcConfig.getLoadBalancer());
            Map<String, Object> requestParams = new HashMap<>();
            requestParams.put("serviceName", serviceName);
            ServiceMetaInfo selectedServiceMetaInfo = loadBalancer.select(requestParams, serviceMetaInfoList);
            System.out.println("服务地址：" + selectedServiceMetaInfo.getServiceAddress());
            // tcp请求
//            RpcResponse rpcResponse = VertxTcpClient.doRequest(rpcRequest, selectedServiceMetaInfo);
            // 使用重试
        RpcResponse rpcResponse;
        try {
            RetryStrategy retryStrategy = RetryStrategyFactory.getInstance(rpcConfig.getRetryStrategy());
             rpcResponse = retryStrategy.deRetry(() ->
                VertxTcpClient.doRequest(rpcRequest, selectedServiceMetaInfo)
            );

        } catch (Exception e) {
            TolerantStrategy tolerantStrategy = ToleranStrategyFactory.getInstance(rpcConfig.getTolerantStrategy());
            rpcResponse = tolerantStrategy.doTolerant(null, e);
        }
        return rpcResponse.getData();
        // 三版本
        // 发送tcp请求
            /*Vertx vertx = Vertx.vertx();
            NetClient netClient = vertx.createNetClient();
            CompletableFuture<RpcResponse> responseFure = new CompletableFuture<>();
            //  8888                                            localhost
            netClient.connect(selectedServiceMetaInfo.getServicePort(), selectedServiceMetaInfo.getServiceHost(),
                    result -> {
                        if (result.succeeded()) {    // 连接成功
                            System.out.println("连接成功");
                            NetSocket socket = result.result();
                            // 发送数据   头是构造的tcp协议   体是 方法名 参数什么的
                            ProtocolMessage<RpcRequest> protocolMessage = new ProtocolMessage<>();
                            ProtocolMessage.Header header = new ProtocolMessage.Header();
                            header.setMagic(ProtocolConstant.PROTOCOL_MAGIC);
                            header.setVersion(ProtocolConstant.PROTOCOL_VERSION);
                            String serializerTo = RpcApplication.getRpcConfig().getSerializer();  // 序列化方式  jdk  json、、
                            int serializerKey = ProtocolMessageSerializerEnum.getEnumByValue(serializerTo).getKey();  // 序列化器的编号
                            header.setSerializer((byte) serializerKey);
                            header.setType((byte) ProtocolMessageTypeEnum.REQUEST.getKey());
                            header.setRequestId(IdUtil.getSnowflakeNextId());
                            protocolMessage.setHeader(header);
                            protocolMessage.setBody(rpcRequest);   //  todo 估计会粘包
                            // 编码
                            try {
                                Buffer encodeBuffer = ProtocolMessageEncoder.encode(protocolMessage);
                                socket.write(encodeBuffer);
                            } catch (Exception e) {
                                throw new RuntimeException("消费端请求编码错误");
                            }


                            // 接收数据
                            socket.handler(buffer -> {
                                //  解码  响应
                                try {
                                    ProtocolMessage<RpcResponse> responseProtocolMessage = (ProtocolMessage<RpcResponse>) ProtocolMessageDecoder.decode(buffer);
                                    responseFure.complete(responseProtocolMessage.getBody());  // 完成
                                } catch (Exception e) {
                                    throw new RuntimeException("消费端响应解码错误");
                                }
                            });
                        } else {
                            throw new RuntimeException("连接失败");
                        }
                    });
            RpcResponse response = responseFure.get();
            netClient.close();    // 关闭连接
            return response.getData();*/
      /*    二版本
            HttpResponse httpResponse = HttpRequest.post(selectedServiceMetaInfo.getServiceAddress())
                    .body(bodyBytes)
                    .execute();
            byte[] result = httpResponse.bodyBytes();

            RpcResponse rpcResponse = serializer.deserialize(result, RpcResponse.class);
            return rpcResponse.getData();*/

    }


}
